---
title: Configuring Expressive Code
---

import { Tabs, TabItem } from '@astrojs/starlight/components'

Expressive Code comes with default settings that should work out of the box for most sites. However, you can customize the configuration to match your needs by providing an options object to Expressive Code.

## How to define your configuration

There are two ways to configure Expressive Code:
- You can pass your options to the initialization function of the integration you are using
- In Astro or Starlight projects, you can also create a file named `ec.config.mjs` in your project's root directory and export your configuration object from there

If both methods are used, both config sources are merged on a per-option basis, with the options from the `ec.config.mjs` file taking precedence.

For the following object options, a deep merge of all nested properties is performed, allowing you to perform granular overrides:
- [`defaultProps`](#defaultprops)
- [`frames`](#frames)
- [`shiki`](#shiki)
- [`styleOverrides`](#styleoverrides)

Also, the following array options are concatenated instead of being replaced:
- [`shiki.langs`](/key-features/syntax-highlighting/#langs)

### Passing options directly

The default method to configure Expressive Code is to pass your options to the initialization function of the integration you are using:

<ConfigVariants settings={`
// You can set configuration options here
themes: ['dracula', 'github-light'],
styleOverrides: {
  // You can also override styles
  borderRadius: '0.5rem',
  frames: {
    shadowColor: '#124',
  },
},
`} />

### Using an `ec.config.mjs` file

In projects based on Astro or Starlight, you also have the option to create a file named `ec.config.mjs` in your project's root directory and export your configuration object as the default export from there:

<ConfigVariants onlyEcConfigFile ins={[]} settings={`
// You can set configuration options here
themes: ['dracula', 'github-light'],
styleOverrides: {
  // You can also override styles
  borderRadius: '0.5rem',
  frames: {
    shadowColor: '#124',
  },
},
`} />

:::note
Using an `ec.config.mjs` file may be required to use the [`Code` component](/key-features/code-component/) if your configuration contains plugins which would not be accessible from the component's scope otherwise. The `Code` component will inform you if this is the case for your configuration.
:::

## Core options

The following options are supported by the core package and all integrations:

### cascadeLayer

<PropertySignature>
- Type: string
- Default: `undefined`
</PropertySignature>

Allows to specify a CSS cascade layer name that should be used for all generated CSS.

If you are using [cascade layers](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Cascade_layers) on your site to control the order in which CSS rules are applied, set this option to a non-empty string, and Expressive Code will wrap all of its generated CSS styles in a `@layer` rule with the given name.

### customizeTheme

<PropertySignature>
- Type: (theme) => void \| [ExpressiveCodeTheme](/reference/core-api/#expressivecodetheme)
- Default: `undefined`
</PropertySignature>

This optional function is called once per theme during engine initialization with the loaded theme as its only argument.

It allows customizing the loaded theme and can be used for various purposes:
- You can change a theme's `name` property to influence the CSS needed to select it (e.g., when using the default settings for `themeCssRoot` and `themeCssSelector`, setting `theme.name = 'dark'` will allow theme selection using `<html data-theme="dark">`).
- You can create color variations of themes by using `theme.applyHueAndChromaAdjustments()`.

You can optionally return an `ExpressiveCodeTheme` instance from this function to replace the theme provided in the configuration. This allows you to create a copy of the theme and modify it without affecting the original instance.

#### Parameters

- **theme**: [`ExpressiveCodeTheme`](/reference/core-api/#expressivecodetheme)

### defaultLocale

<PropertySignature>
- Type: string
- Default: `'en-US'`
</PropertySignature>

The locale that should be used for text content.

### defaultProps

<PropertySignature>
- Type: Partial\<[`ExpressiveCodeBlockProps`](#expressivecodeblockprops)\> & \{ overridesByLang: Object \}
- Default: `undefined`
</PropertySignature>

An optional set of default props for all code blocks in your project.

For example, setting this to `{ wrap: true }` enables word wrapping on all code blocks by default, saving you from having to manually set this option on every single code block.

#### Object properties

##### overridesByLang

<PropertySignature>
- Type: Record\<string, Partial\<[`ExpressiveCodeBlockProps`](#expressivecodeblockprops)\>\>
</PropertySignature>
Allows to override the default props based on a code block's syntax highlighting language.

Use the language IDs as keys and an object containing the props as values. The keys also support specifying multiple language IDs separated by commas to apply the same props to multiple languages.

**Example**
```js
defaultProps: {
  wrap: true,
  overridesByLang: {
    'bash,sh,zsh': { wrap: false }
  }
}
```

### logger

<PropertySignature>
- Type: Partial\<[ExpressiveCodeLoggerOptions](#available-logger-options)\>
</PropertySignature>

Allows to customize how Expressive Code logs messages. The default implementation logs all messages to the console and prepends them with the label `expressive-code` like this:

```text
[expressive-code] This is a debug message.
```

#### Available logger options

- **label**: `string`\
  The label to use as a prefix for all log messages. Defaults to `'expressive-code'`.
- **debug**: `(message: string) => void`\
  A function to log a debug message.
- **info**: `(message: string) => void`\
  A function that logs an info message.
- **warn**: `(message: string) => void`\
  A function that logs a warning message.
- **error**: `(message: string) => void`\
  A function that logs an error message.

### minSyntaxHighlightingColorContrast

<PropertySignature>
- Type: number
- Default: `5.5`
</PropertySignature>

Determines if Expressive Code should process the syntax highlighting colors of all themes to ensure an accessible minimum contrast ratio between foreground and background colors.

The default of `5.5` ensures a contrast ratio of at least 5.5:1. You can change the desired contrast ratio by providing another value, or turn the feature off by setting this option to `0`.

### plugins

<PropertySignature>
- Type: ([ExpressiveCodePlugin](/reference/plugin-api/#expressivecodeplugin) \| [ExpressiveCodePlugin](/reference/plugin-api/#expressivecodeplugin)[])[]
- Default: `[]`
</PropertySignature>

An optional array of plugins that should be used when rendering code blocks.

To add a plugin, import its initialization function and call it inside this array.

If the plugin has any configuration options, you can pass them to the initialization function as an object containing your desired property values.

If any nested arrays are found inside the `plugins` array, they will be flattened before processing.

### styleOverrides

<PropertySignature>
- Type: [StyleOverrides](/reference/style-overrides/)
- Default: `{}`
</PropertySignature>

An optional set of style overrides that can be used to customize the appearance of the rendered code blocks without having to write custom CSS.

See the [Style Overrides](/reference/style-overrides/) page for more details.

### ~~theme~~

<PropertySignature>
- Type: [ExpressiveCodeTheme](/reference/core-api/#expressivecodetheme)
</PropertySignature>

:::caution[Deprecated]
Efficient multi-theme support is now a core feature, so the `theme` option
was deprecated in favor of the new array `themes`. Please migrate your existing config
to use `themes` and ensure it is an array. If you only need a single theme, your `themes`
array can contain just this one theme. However, please consider the benefits of providing
multiple themes. See the `themes` option for more details.
:::

### themeCssRoot

<PropertySignature>
- Type: string
- Default: `':root'`
</PropertySignature>

Allows to customize the base selector used to scope theme-dependent CSS styles.

The default selector `':root'` ensures that all required CSS variables are globally available.

### themeCssSelector

<PropertySignature>
- Type: false \| ((theme, context) => string \| false)
- Default: ``(theme) => `[data-theme='${theme.name}']` ``
</PropertySignature>

Allows to customize the selectors used to manually switch between multiple themes.

These selectors are useful if you want to allow your users to choose a theme instead of relying solely on the media query generated by `useDarkModeMediaQuery`.

You can add a theme selector either to your `<html>` element (which is targeted by the `themeCssRoot` default value of `:root`), and/or any individual code block wrapper.

For example, when using the default settings, selecting the theme `github-light` for the entire page would look like this:
```html
<html data-theme="github-light">
```

If your site's theme switcher requires a different approach, you can customize the selectors using this option. For example, if you want to use class names instead of a data attribute, you could set this option to a function that returns `.theme-${theme.name}` instead.

If you want to prevent the generation of theme-specific CSS rules altogether, you can set this to `false` or return it from the function.

### themes

<PropertySignature>
- Type: [ExpressiveCodeTheme](/reference/core-api/#expressivecodetheme)[]
</PropertySignature>

The color themes that should be available for your code blocks.

CSS variables will be generated for all themes, allowing to select the theme to display using CSS. If you specify one dark and one light theme, a `prefers-color-scheme` media query will also be generated by default. You can customize this to match your site's needs through the `useDarkModeMediaQuery` and `themeCssSelector` options.

Defaults to the `github-dark` and `github-light` themes.

### useDarkModeMediaQuery

<PropertySignature>
- Type: boolean
</PropertySignature>

Determines if CSS code is generated that uses a `prefers-color-scheme` media query to automatically switch between light and dark themes based on the user's system preferences.

Defaults to `true` if your `themes` option is set to one dark and one light theme (which is the default), and `false` otherwise.

### useStyleReset

<PropertySignature>
- Type: boolean
- Default: `true`
</PropertySignature>

Determines if code blocks should be protected against influence from site-wide styles.

Defaults to `true`, which causes Expressive Code to use the declaration `all: revert` to revert all CSS properties to the values they would have had without any site-wide styles. This ensures the most predictable results out of the box.

You can set this to `false` if you want your site-wide styles to influence the code blocks.

### useThemedScrollbars

<PropertySignature>
- Type: boolean
- Default: `true`
</PropertySignature>

Whether the themes are allowed to style the scrollbars.

If set to `false`, scrollbars will be rendered using the browser's default style.

Note that you can override the individual scrollbar colors defined by the theme using the `styleOverrides` option.

### useThemedSelectionColors

<PropertySignature>
- Type: boolean
- Default: `false`
</PropertySignature>

Whether the themes are allowed to style selected text.

By default, Expressive Code renders selected text in code blocks using the browser's default style to maximize accessibility. If you want your selections to be more colorful, you can set this option to `true` to allow using theme selection colors instead.

Note that you can override the individual selection colors defined by the theme using the `styleOverrides` option.

## Options of `expressive-code`

The `expressive-code` package bundles the core package with all default plugin packages. To allow controlling the plugins, it also supports the following options in addition to the ones above:

### frames

<PropertySignature>
- Type: boolean \| [PluginFramesOptions](/key-features/frames/#available-plugin-options)
- Default: `true`
</PropertySignature>

The Frames plugin adds an editor or terminal frame around code blocks, including an optional title displayed as a tab or window caption.

This plugin is enabled by default. Set this to `false` to disable it. You can also configure the plugin by setting this to an options object.

### shiki

<PropertySignature>
- Type: boolean \| [PluginShikiOptions](/key-features/syntax-highlighting/#available-plugin-options)
- Default: `true`
</PropertySignature>

The Shiki plugin adds syntax highlighting to code blocks.

This plugin is enabled by default. Set this to `false` to disable it. You can also configure the plugin by setting this to an options object.

### textMarkers

<PropertySignature>
- Type: boolean
- Default: `true`
</PropertySignature>

The Text Markers plugin allows to highlight lines and inline ranges in code blocks in various styles (e.g. marked, inserted, deleted).

This plugin is enabled by default. Set this to `false` to disable it.

## Options of `rehype-expressive-code`

In addition to the options above, the rehype integration also supports the following options:

### customCreateBlock

<PropertySignature>
- Type: (\{ input, file }) => [ExpressiveCodeBlock](/reference/core-api/#expressivecodeblock) \| Promise\<[ExpressiveCodeBlock](/reference/core-api/#expressivecodeblock)\>
- Default: `undefined`
</PropertySignature>

This optional function allows you to customize how `ExpressiveCodeBlock` instances are created from code blocks found in the Markdown document.

The function is expected to return an `ExpressiveCodeBlock` instance or a promise resolving to one.

#### Parameters

- **input**: [ExpressiveCodeBlockOptions](/reference/core-api/#expressivecodeblockoptions)\
  Block data for the `ExpressiveCodeBlock` constructor.

- **file**: VFileWithOutput\<null\>\
  A `VFile` instance representing the Markdown document.

### customCreateRenderer

<PropertySignature>
- Type: (options) => Promise\<RehypeExpressiveCodeRenderer\> \| RehypeExpressiveCodeRenderer
- Default: `undefined`
</PropertySignature>

This advanced option allows you to influence the rendering process by creating your own `ExpressiveCode` instance or processing the base styles and JS modules added to every page.

The return value will be cached and used for all code blocks in the document.

#### Parameters

- **options**: `RehypeExpressiveCodeOptions`

### getBlockLocale

<PropertySignature>
- Type: (\{ input, file }) => string \| undefined \| Promise\<string \| undefined\>
- Default: `undefined`
</PropertySignature>

This optional function provides support for multi-language sites by allowing you to customize the locale used for a given code block.

If the function returns `undefined`, the default locale provided in the Expressive Code configuration is used.

#### Parameters

- **input**: [ExpressiveCodeBlockOptions](/reference/core-api/#expressivecodeblockoptions)\
  Block data for the `ExpressiveCodeBlock` constructor.

- **file**: VFileWithOutput\<null\>\
  A `VFile` instance representing the Markdown document.

### tabWidth

<PropertySignature>
- Type: number
- Default: `2`
</PropertySignature>

The number of spaces that should be used to render tabs.

Any tabs found in code blocks in your markdown/MDX documents will be replaced with the specified number of spaces. This ensures that the code blocks are rendered consistently across browsers and platforms.

If you want to preserve tabs in your code blocks, set this option to 0.

### themes

<PropertySignature>
- Type: [ThemeObjectOrShikiThemeName](/api/rehype-expressive-code/type-aliases/themeobjectorshikithemename/)[]
- Default: `['github-dark', 'github-light']`
</PropertySignature>

The color themes that should be available for your code blocks.

CSS variables will be generated for all themes, allowing to select the theme to display using CSS. If you specify one dark and one light theme, a `prefers-color-scheme` media query will also be generated by default. You can customize this to match your site's needs through the `useDarkModeMediaQuery` and `themeCssSelector` options.

The following item types are supported in this array:
- any theme name bundled with Shiki (e.g. `dracula`)
- any theme object compatible with VS Code or Shiki (e.g. imported from an NPM theme package)
- any ExpressiveCodeTheme instance (e.g. using `ExpressiveCodeTheme.fromJSONString(...)` to load a custom JSON/JSONC theme file yourself)

## Options of `astro-expressive-code`

In addition to the options above, the Astro integration also supports the following options:

### emitExternalStylesheet

<PropertySignature>
- Type: boolean
- Default: `true`
</PropertySignature>

Determines if the styles required to display code blocks should be emitted into a separate CSS file rather than being inlined into the rendered HTML of the first code block per page.

This is recommended for sites containing multiple pages with code blocks, as it will reduce the overall footprint of the site when navigating between pages.

The generated URL is located inside Astro's assets directory and includes a content hash so it can be cached indefinitely by browsers. If you are using the default values for the Astro config options `base`, `build.assets`, `build.assetsPrefix`, the resulting URL will be `/_astro/ec.{hash}.css`.

:::caution[Important]
To actually benefit from caching, please ensure that your hosting provider serves the contents of the assets directory as immutable files with a long cache lifetime, e.g. `Cache-Control: public,max-age=31536000,immutable`.
:::

## Options of the Starlight integration

In addition to the options above, the Starlight integration provides two themes (`starlight-dark` and `starlight-light`) and options (`useStarlightDarkModeSwitch` and `useStarlightUiThemeColors`) that are specific to Starlight.

Please refer to the [Starlight Configuration Reference](https://starlight.astro.build/reference/configuration/#expressivecode) for more details.

## Referenced types

````yml include
name: "ExpressiveCodeBlockProps"
headingLevel: 3
````
